﻿/**
 * Classe permettant de faire des requêtes ajax simplifiés
 * 
 * @param {String} url l'url
 * @param {String} type Request.POST ou Request.GET
 * @param {Object} params les paramètres de l'URL. Exemple: {param1: "valeur1", param2: "valeur2"}
 * @param {Object} headers les headers supplémentaires
 */
function Request(url, type, params, headers)
{
	/**
	 * L'URL à contacter
	 */
	var _url;
	/**
	 * Les paramètres à envoyer
	 */
	var _params;
	/**
	 * Le type de requête (POST / GET)
	 */
	var _type;
	
	/**
	 * Headers à envoyé en supplémentaire
	 */
	var _headers;
	
	/**
	 * Headers par défaut
	 */
	var _headers_default = {
		"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
		//"User-Agent": "Mozilla/5.0 AppleWebKit/535.7 (KHTML, like Gecko) Chrome/16.0.912.12 Safari/535.7"
	}
	
	/**
	 * L'objet XMLHttpRequest associé
	 */
	var _req;
	
	/**
	 * Evènement à la fin du chargement de la requête
	 */
	this.onload = null;
	
	/**
	 * Evènement à chaque fois qu'une progression est faite
	 */
	this.onprogress = null;
	
	var _this = this;
	
	/**
	 * Renvoie les vrai bytes envoyé par le site
	 * 
	 * Nécessite de mettre le paramètre responseType à 'bytes':
	   req = new Request("http://monadresse",Request.GET)
	   req.responseType = "bytes"
	 * 
	 * @return {String} la chaîne de caractères avec les vrai bytes
	 */
	this.getResponseBytes = function()
	{
		var str = this.getResponseText();
		var result = str;
		if (this.responseType == "bytes")
		{
		 	result = "";
		 	for (var i = 0; i < str.length; i++)
		 	{
		 		var b = (str.charCodeAt(i) & 0xFF)
		 		result += String.fromCharCode(b)
		 	}
		}
		return result;
	};
	
	/**
	 * Renvoie l'objet Document du DOM correspondant au responseText
	 * 
	 * @return {Document} le document associé
	 */
	
	this.getResponseDocument = function()
	{
		var text = _req.responseText;
		return _getDocumentFromHTML(text);
	};
	
	/**
	 * Parse l'HTML
	 * 
	 * Utilise le parseur du navigateur via une Iframe
	 * 
	 * @param {String} content l'HTML a parser
	 */
	function _parseHTML(content)
	{
		var iframe = document.createElement("iframe");
	    document.body.appendChild(iframe); 
	
		var doc = iframe.document;
	    
	    if(iframe.contentDocument)
	        doc = iframe.contentDocument; // For NS6
	    else if(iframe.contentWindow)
	        doc = iframe.contentWindow.document; // For IE5.5 and IE6
	    // Put the content in the iframe
	    doc.open();
	    doc.writeln(content);
	    doc.close(); 
		
		//document.body.removeChild(iframe);
		
		return doc;
	}
	
	/**
	 * Parse un fichier HTML et renvoie le Document associé
	 * 
	 * Effectue quelques remplacements pour ne pas charger les images / css et scripts
	 * 
	 * @param {String} content l'HTML à parser
	 * @param {}
	 */
	function _getDocumentFromHTML(content)
	{
		var page = content;
		
		var liste_src = [
			["script", "src", "_src"],
			["link", "href", "_href"],
			["img", "src", "_src"]
		];
		
		for (var i = 0; i < liste_src.length; i++)
		{
			var tag = liste_src[i]
			var nametag = tag[0]
			var attr = tag[1]
			var new_attr = tag[2]
			
			var regexp = new RegExp("<"+nametag+"([^>]*)"+attr+'="([^"]*)"([^>]*)>','g')		
			page = page.replace(regexp,"<"+nametag+"$1"+new_attr+'="$2"$3>')
		}
		
		// Remplacement du style par _style
		regexp_style = new RegExp('<([a-zA-Z-]*)([^>]*)style="([^"]*)"([^>]*)>','gim')
		page = page.replace(regexp_style,"<$1$2"+'_style="$3"$4>')
		
		// Remplacement des balises javascript sans src, pour éviter leur exécution
		regexp_script_no_src = /<script([^>]*)>/g
		page = page.replace(regexp_script_no_src,'<script$1 src="blank.js">')
		
		regexp_tagstyle = /<style([^>]*)>/ig
		page = page.replace(regexp_tagstyle,'<!--<style$1>')
		
		regexp_tagstyle_end = /<\/style([^>]*)>/ig
		page = page.replace(regexp_tagstyle_end,'</style$1>-->')
		
		Request.lastpage = page;
		
		// Parsage de l'HTML
		doc = _parseHTML(page)
		
		// <script([^>]*)src="([^"]*)"([^>]*)>
		// <script$1_src="$2"$3>
		// Suppression des src blank.js factifs
		/*var scripts = doc.getElementsByTagName("script")
		for (var i = 0; i < scripts.length; i++)
		{
			if (scripts[i].getAttribute("src") == "blank.js")
				scripts[i].removeAttribute("src");
		}*/
		
		return doc;
	}
	
	/**
	 * Récupère la réponse "text" envoyé par le site contacté
	 *
	 * @param {String} La réponse reçue
	 */
	this.getResponseText = function()
	{
		return _req.responseText;
	};
	
	/**
	 * Récupère le status (200, 404, ...) envoyé par le site contacté
	 *
	 * @return {String} Le status reçu
	 */
	this.getStatus = function()
	{
		return _req.status;
	};
	
	/**
	 * Récupère les paramètres envoyés à l'adresse
	 *
	 * @return {String} Les paramètres envoyés
	 */
	this.getParams = function()
	{
		return _params;
	};
	
	/**
	 * Renvoie l'objet XMLHttpRequest généré
	 * 
	 * @return {XMLHttpRequest} l'objet XMLHttpRequest
	 */
	this.getXMLHttpRequest = function()
	{
		return _req;
	};
	
	/**
	 * Lance la requête à l'adresse indiqué
	 */
	this.start = function()
	{
		var _params = _getParamsForRequest();
		
		
		// L'ajout des paramètres dans l'URL en GET
		var req = new XMLHttpRequest();
		if (_type == Request.GET)
		{
			// Si le ? est déjà présent, on ajoute un "&"
			if (_url.indexOf("?") != -1)
				_url += "&"
			else
				_url += "?"
			
			_url += _params;
		}
		
			
		req.open(_type,_url,true);
		if (this.responseType)
		{
			if (this.responseType == "bytes")
				req.overrideMimeType('text/plain; charset=x-user-defined');
			else
				req.responseType = this.responseType;
		}
		
		// Le content-type pour Request.POST
		if (_type == Request.POST)
			req.setRequestHeader("Content-type","application/x-www-form-urlencoded");
		
		// Ajout des headers personnalisés
		for (var i in _headers)
		{
			if (typeof(_headers[i]) != "function")
				req.setRequestHeader(i,_headers[i]);			
		}
		
		// Ajout des headers par défaut
		_addDefaultHeaders(req);
		
		// req.setRequestHeader("Accept","application/json, text/javascript, */*");
		req.onload = _onload;
		req.onprogress = _onprogress;
		req.onerror = _onerror;
		
		_req = req;
		
		if (_type == Request.POST)
			req.send(_params);
		else
			req.send(null)
	};
	
	/**
	 * Ajoute les headers par défaut pour une requête
	 * 
	 * @param {XMLHttpRequest} req la requête
	 */
	function _addDefaultHeaders(req)
	{
		for (var i in _headers_default)
		{
			if (!_headers[i] && typeof(_headers[i]) != "function")
				req.setRequestHeader(i,_headers_default[i]);
		}
	}
	
	/**
	 * Ecouteur déclenché à la fin du chargement de la requête XMLHttpRequest
	 *
	 * @param {Event} e L'Event envoyé par XMLHttpRequest
	 */
	function _onload(e)
	{
		// Exécution de la fonction associé à l'évènement onload de l'objet
		if (typeof(_this.onload) == "function")
			_this.onload(new RequestEvent(e,_this));
	};
	
	/**
	 * Ecouteur déclenché lors d'une progression de la requête XMLHttpRequest
	 * 
	 * @param {Event} e l'Event renvoyé par XMLHttpRequest
	 */
	function _onprogress(e)
	{
		if (typeof(_this.onprogress) == "function")
			_this.onprogress(new RequestEvent(e,_this));
		
		if (e.lengthComputable)
			console.log(e.loaded+"/"+e.total)
		else
			console.log("Loaded: "+e.loaded)
	}
	
	/**
	 * Renvoie les paramètres formattés pour la requête
	 *
	 * @return {String} la chaîne de caractère comportant les paramètres formattés
	 */
	function _getParamsForRequest()
	{
		var str = "";
		for (var index in _params)
		{
			// Ajout du séparateur "&"
			if (str != "") str += "&";
			
			// Ajout du paramètre au format name=value
			str += index+"="+_params[index];
		}
		return str;
	};
	
	/**
	 * Ecouteur déclenché lorsqu'une erreur survient lors de la requête
	 * 
	 * Déclenche la fonction onload
	 * 
	 * @param {Event} e l'Event renvoyé par XMLHttpRequest
	 */
	function _onerror(e)
	{
		_onload(e);
	};
	/**
	 * Constructeur de la classe
	 *
	 * @param {String} url L'URL à contacter
	 * @param {String} type Request.POST ou Request.GET
	 * @param {Object} params Les différents paramètres à envoyés
	 */
	function _construct(url, type, params, headers)
	{
		_url = url;
		_type = type;
		_params = params;
		_headers = headers;
		
		if (!headers)
			_headers = {}
		
		if (!params)
			_params = {}
	};

	
	
	// Appel du constructeur
	_construct(url,type, params, headers);
	
};

Request.POST = "POST";
Request.GET = "GET";